home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
051-075
/
069
/
spool
/
spooler.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-13
|
11KB
|
429 lines
/* SPOOLER.c - asynchronous file print program */
/*
** Date written: 04/23/86
** Author: Tim Holloway
** Compuserve: 73026,2026
** Bix: tholloway
** Fido node: 112/1 (Casa Mi Amiga).
**
** As featured in Ami Project Magazine.
**
** Version: 1.1
**
** Copyright (C) 1986, by Tim Holloway. This program may be
** freely distributed for non-commercial use only. Use for commercial
** purposes without the express permission of the author is a violation
** of copyright law.
**
** Description:
** This program is the intermediary between user requests submitted
** via the SPOOL program, and the printers driven by copies of the
** PRTSPOOL program. Three queues are maintained: the logged-in user
** queue has an entry for each user (SPOOL or PRTSPOOL) logged into
** SPOOLER. The filename queue is where filenames passed from SPOOL
** are stored until they can be passed on to PRTSPOOLs. Finally, the
** waiting-printer queue is where requests for work from PRTSPOOL
** are held.
**
** This program illustrates message passing and waiting for messages.
** Each message is the name of a file. The named file will be printed,
** unless the name is SHUTDOWN, which causes SPOOLER to cease
** accepting login requests, and to respond to further messages with
** forced logouts. SPOOL shuts down completely when the login queue
** has at last been emptied.
**
** Change History:
**
** 11/19/86, TFH - added logic to FreeStruct SPOOL queue
** entries when they were removed from the SPOOL queue. How
** embarassing! Also, removed all printfs - does all talking via
** Intuition now.
**
** Usage: RUN SPOOLER
*/
#include <exec/types.h>
#include <exec/exec.h>
#include <exec/alerts.h>
#include <libraries/dosextens.h>
#include "stdio.h"
#include "spool.h"
#define NOT ! /* A la RJ Mical */
#define USER_NAME_LENGTH 33 /* maximum length of a logged user name */
/*
** The following is an information hider - it insulates the workings
** of this program against changes in the DOS and from compiler
** dependencies. Also makes program more readable.
*/
#define on_port(mport) (1L << mport->mp_SigBit)
/* A convenient allocator for structures: */
#define AllocStruct(structype, pool) (structype *) \
AllocMem (sizeof(structype), pool)
/* And its converse... */
#define FreeStruct(area, structype) FreeMem(area, sizeof(structype))
/* Hide the details of test for an empty list */
#define EmptyList(list) (list.lh_Head->ln_Succ == NULL)
#define streq(a,b) (strcmp(a,b) == 0) /* an old favorite */
/*
** Logged-in user queue element definition:
*/
typedef struct {
struct Node lu_node;
char lu_name[USER_NAME_LENGTH];
} logged_user;
/* Prototypes. Lie slightly about function return types. */
extern logged_user *Find_Name(struct List *, TEXT *);
extern SPOOLmsg *RemHead (struct List *),
*GetMsg (struct MsgPort *);
/* Global variables. */
BOOL
spooler_running;
spooler_closing_down;
static void
make_id (packet, str) /* create a unique login ID */
SPOOLmsg *packet; /* based on the sender's reply port address */
TEXT *str;
{
sprintf (str, "SPOOL User %lx", &packet->minfo.mn_ReplyPort);
}
static void
error (msg) /* report error */
TEXT *msg;
{
Gripe ("SPOOLER:", msg, "");
}
/*************************************************************************
** **
** Log users in and out. Users are logged to ensure that nobody **
** tries to send spool requests once the spooler starts closing **
** down. **
** **
*************************************************************************/
struct List login_list; /* anchor the list of logged-in users */
struct List file_queue; /* ditto the list of filenames to spool */
struct List waiting_printers; /* unemployed printer list */
static void
login(packet)
register SPOOLmsg *packet;
{
register logged_user *user;
packet->log_status = LOG_OUT; /* assume the worst */
if (NOT spooler_closing_down)
{
/* printf ("Log in: "); */
user = AllocStruct (logged_user, MEMF_PUBLIC | MEMF_CLEAR);
if (user == NULL)
error ("Couldn't get memory to log in user");
else
{
user->lu_node.ln_Name = user->lu_name;
user->lu_node.ln_Type = NT_UNKNOWN;
user->lu_node.ln_Pri = 0;
make_id (packet, user->lu_name);
AddTail (&login_list, user);
/* printf ("%s completed\n", user->lu_name); */
packet->log_status = LOGGED;
}
}
}
static void
logout(packet)
register SPOOLmsg *packet;
{
char user_id[USER_NAME_LENGTH];
register logged_user *user;
make_id (packet, user_id);
user = (logged_user *) FindName (&login_list, user_id);
if (user == NULL)
{
error ("Logout failed - could not find user ID:");
error (user_id);
}
else
{
/* printf ("%s logged out.\n", user_id); */
Remove(user); /* ... from the logged-user list */
FreeStruct(user, logged_user);
packet->log_status = LOG_OUT;
if (EmptyList(login_list) && spooler_closing_down)
spooler_running = FALSE;
}
}
/*************************************************************************
** **
** Spooler shutdown routines. **
** **
*************************************************************************/
static void
purge_queues() /* throw away any outstanding SPOOL requests */
{ /* modified v1.1 */
SPOOLmsg *qp;
while ( (qp = (SPOOLmsg *) RemHead(&file_queue)) != NULL)
FreeStruct(qp, SPOOLmsg);
}
static void
terminate_printers() /* tell the printers to get lost! */
{
register SPOOLmsg *bail_out;
while (
(bail_out = (SPOOLmsg *)RemHead(&waiting_printers))
!=
NULL
)
{
/* printf ("Force off PRT %lx\n", bail_out); */
logout(bail_out); /* remove from log */
bail_out->log_status = LOG_OUT;
ReplyMsg(bail_out);
}
}
/*************************************************************************
** **
** Process inbound SPOOL requests. **
** If somebody wants the request, pass it on, else make a copy **
** of it, and queue the copy. **
** **
*************************************************************************/
static void
pass_request(packet)
register SPOOLmsg *packet;
{
register SPOOLmsg *msg_requested;
if ( (msg_requested= RemHead(&waiting_printers)) == NULL)
{
msg_requested =
AllocStruct (SPOOLmsg, MEMF_PUBLIC);
movmem (packet, msg_requested, sizeof(SPOOLmsg));
/* printf ("Queuing request for %s\n", packet->filename); */
AddTail (&file_queue, msg_requested);
}
else /* send the name to the PRTSPOOL's query */
{
strcpy (msg_requested->filename, packet->filename);
ReplyMsg (msg_requested);
}
}
/*************************************************************************
** **
** Process inbound SPOOL requests. **
** **
*************************************************************************/
static void
handle_input(packet)
register SPOOLmsg *packet;
{
/* printf ("Inbound message from %lx\n", packet); */
switch (packet->log_status)
{
case LOG_IN:
login (packet);
break;
case LOG_OUT:
logout (packet);
break;
case LOGGED:
if (spooler_closing_down)
logout(packet); /* sorry! */
else
if (streq(packet->filename, SHUTDOWN))
{
spooler_closing_down = TRUE;
purge_queues();
terminate_printers();
}
else
pass_request (packet);
break;
default: error ("SPL: Invalid log request");
}
ReplyMsg (packet); /* return to owner! */
}
/*************************************************************************
** **
** Process outbound SPOOL requests. **
** **
** Notice that since the PRTSPOOL messages contain List nodes, **
** they can be queued directly! **
** **
*************************************************************************/
static void
prt_request(packet)
register SPOOLmsg *packet;
{
register SPOOLmsg *msg_requested;
if ( (msg_requested= RemHead(&file_queue)) == NULL)
{
/* printf ("Queuing PRT request from %lx.\n", packet); */
AddTail (&waiting_printers, packet);
}
else
{
/* printf ("dequeueing and outputting %s\n", msg_requested->filename); */
strcpy (packet->filename, msg_requested->filename);
FreeStruct (msg_requested, SPOOLmsg); /* V1.1 */
ReplyMsg (packet);
}
}
/*************************************************************************
** **
** Process PRTSPOOL requests. **
** **
*************************************************************************/
static void
handle_output(packet)
register SPOOLmsg *packet;
{
/* printf ("PRTSPOOL message from %lx\n", packet); */
switch (packet->log_status)
{
case LOG_IN:
login (packet);
break;
case LOG_OUT:
logout (packet);
break;
case LOGGED:
if (spooler_closing_down)
logout(packet); /* sorry! */
else
{
prt_request (packet);
return; /* reply done in prt_request */
}
break;
default: error ("PRT: Invalid log request");
}
ReplyMsg (packet); /* return to owner! */
}
/*************************************************************************
** **
** Gentlemen, start your SPOOLers. **
** **
*************************************************************************/
struct Library *IntuitionBase, *OpenLibrary();
void
main (argc, argv)
int argc;
char *argv[];
{
struct MsgPort *FindPort(), *CreatePort(), *inport, *outport;
SPOOLmsg *packet;
struct Process *myprocess, *FindTask();
if ( (IntuitionBase = OpenLibrary("intuition.library", 0)) == NULL)
{
Alert (AT_Recovery + AG_OpenLib + AO_Intuition, NULL);
exit(20);
}
/* it doesn't hurt to run multiple SPOOLERS at once -
but why bother? Only one will get the messages! */
if(FindPort(SPOOL_ME) != NULL)
{
error ("SPOOLER is already active!");
goto abort;
}
if ((inport = CreatePort(SPOOL_ME,0)) == NULL)
{
error ("Unable to create spool message port\n");
goto abort;
}
if ((outport = CreatePort(GIMME_A_FILE,0)) == NULL)
{
error ("Unable to create spool message port\n");
DeletePort (inport);
goto abort;
}
NewList (&file_queue);
NewList (&login_list);
NewList (&waiting_printers);
/* raise priority - this program is low-overhead (mostly Waiting) */
myprocess = FindTask(NULL);
(void) SetTaskPri (myprocess, SPOOLER_PRIORITY);
/* printf ("input message port for %s is at %lx\n", SPOOL_ME, inport); */
for (spooler_running = TRUE; spooler_running ; )
{
/* printf ("Wait for port...\n"); */
Wait (on_port(inport) | on_port(outport)); /* '|', NOT '||' ! */
while ( (packet = GetMsg (inport)) != NULL) handle_input(packet);
while ( (packet = GetMsg (outport)) != NULL) handle_output(packet);
}
/* printf ("Spooling has been terminated\n"); */
DeletePort (inport);
DeletePort (outport);
abort:
CloseLibrary(IntuitionBase);
}